#ifndef OPERATION_H
#define OPERATION_H
#include "DerivationTree.h"
#include "CopyPointer.h"
#include <list>

template<typename Parser>
class Operation {
public://TODO delete memory
	Operation(Parser* _p) : p(_p) { }

	void save() {
		p->save();
	}

	void restore() {
		p->restore();
	}

	void clear() {
		p->clear();
	}

	Parser* getParser() const { return p; }
private:
	Parser* p;
};

template<typename Parser>
class IntegerNumber : public Operation<Parser> {
public:
	IntegerNumber(Parser* _p) : Operation<Parser>(_p) { }

	bool operator()(ParseStream* x, unsigned int start, unsigned int end) const {
		char *number = new char[end-start];
		int i = 0;
		while (x->getPosition() < end) {
			number[i] = x->get();
			x->next();
			++i;
		}
		AutoPointer<NodeTree> nmb(new IntegerNode(number, end-start));//TODO considerare memoria
		this->getParser()->push(nmb);
		return true;
	}
};

template<typename Parser>
class FloatNumber : public Operation<Parser> {
public:
	FloatNumber(Parser* _p) : Operation<Parser>(_p)  { }

	bool operator()(ParseStream* x, unsigned int start, unsigned int end) const {
		char *number = new char[end-start];
		int i = 0;
		while (x->getPosition() < end) {
			number[i] = x->get();
			x->next();
			++i;
		}
		AutoPointer<NodeTree> nmb(new FloatNode(number, end-start));//TODO considerare memoria
		this->getParser()->push(nmb);
		return true;
	}
};

template<typename Parser>
class VariableAllocator : public Operation<Parser> {
public:
	VariableAllocator(Parser* _p) : Operation<Parser>(_p) { }

	bool operator()(ParseStream* x, unsigned int start, unsigned int end) const {
		char *name = new char[end-start+1];
		int i = 0;
		while (x->getPosition() < end) {
			name[i] = x->get();
			x->next();
			++i;
		}
		name[i] = 0;
		AutoPointer<NodeTree> nmb(new VariableNode(name, end-start+1));//TODO check memory
		this->getParser()->push(nmb);
		return true;
	}
};

template<typename Parser>
class Sum : public Operation<Parser> {
public:
	Sum(Parser* _p) : Operation<Parser>(_p) { }

	bool operator()(ParseStream* , unsigned int , unsigned int ) const {
		AutoPointer<NodeTree> a = this->getParser()->top();
		this->getParser()->pop();
		AutoPointer<NodeTree> b = this->getParser()->top();
		this->getParser()->pop();
		this->getParser()->push( AutoPointer<NodeTree>(new PlusNode(b, a)) );
		return true;
	}
};

template<typename Parser>
class Times : public Operation<Parser> {
public:
	Times(Parser* _p) : Operation<Parser>(_p) { }

	bool operator()(ParseStream* , unsigned int , unsigned int ) const {
		AutoPointer<NodeTree> a = this->getParser()->top();
		this->getParser()->pop();
		AutoPointer<NodeTree> b = this->getParser()->top();
		this->getParser()->pop();
		this->getParser()->push( AutoPointer<NodeTree>(new StarNode(b, a)) );
		return true;
	}
};

template<typename Parser>
class Power : public Operation<Parser> {
public:
	Power(Parser* _p) : Operation<Parser>(_p) { }

	bool operator()(ParseStream* , unsigned int , unsigned int ) const {
		AutoPointer<NodeTree> a = this->getParser()->top();
		this->getParser()->pop();
		AutoPointer<NodeTree> b = this->getParser()->top();
		this->getParser()->pop();
		this->getParser()->push( AutoPointer<NodeTree>(new PowerNode(b, a)) );
		return true;
	}
};

template<typename Parser>
class Minus : public Operation<Parser> {
public:
	Minus(Parser* _p) : Operation<Parser>(_p) { }

	bool operator()(ParseStream* , unsigned int , unsigned int ) const {
		AutoPointer<NodeTree> a = this->getParser()->top();
		this->getParser()->pop();
		AutoPointer<NodeTree> b = this->getParser()->top();
		this->getParser()->pop();
		this->getParser()->push( AutoPointer<NodeTree>(new MinusNode(b,a)) );
		return true;
	}
};

template<typename Parser>
class UnaryMinus : public Operation<Parser> {
public:
	UnaryMinus(Parser* _p) : Operation<Parser>(_p) { }

	bool operator()(ParseStream* , unsigned int , unsigned int ) const {
		AutoPointer<NodeTree> a = this->getParser()->top();
		this->getParser()->pop();
		this->getParser()->push( AutoPointer<NodeTree>(new UnaryMinusNode(a)) );
		return true;
	}
};

template<typename Parser>
class Divide : public Operation<Parser> {
public:
	Divide(Parser* _p) : Operation<Parser>(_p) { }

	bool operator()(ParseStream* , unsigned int , unsigned int ) const {
		AutoPointer<NodeTree> a = this->getParser()->top();
		this->getParser()->pop();
		AutoPointer<NodeTree> b = this->getParser()->top();
		this->getParser()->pop();
		this->getParser()->push(AutoPointer<NodeTree>(new DivideNode(b, a)));
		return true;
	}
};

template<typename Parser>
class Equal : public Operation<Parser> {
public:
	Equal(Parser* _p) : Operation<Parser>(_p) { }

	bool operator()(ParseStream* , unsigned int , unsigned int ) const {
		AutoPointer<NodeTree> a = this->getParser()->top();
		this->getParser()->pop();
		AutoPointer<NodeTree> b = this->getParser()->top();
		this->getParser()->pop();
		this->getParser()->push( AutoPointer<NodeTree>(new EqualNode(b, a)) );
		return true;
	}
};

template<typename Parser>
class Colon : public Operation<Parser> {
public:
	Colon(Parser* _p) : Operation<Parser>(_p) { }

	bool operator()(ParseStream* , unsigned int , unsigned int ) const {
		AutoPointer<NodeTree> a = this->getParser()->top();
		this->getParser()->pop();
		AutoPointer<NodeTree> b = this->getParser()->top();
		this->getParser()->pop();
		this->getParser()->push( AutoPointer<NodeTree>(new ColonNode(b, a)) );
		return true;
	}
};

/*template<typename Parser>
class FunctionName : public Operation<Parser> {
public:
	FunctionName(Parser* _p) : Operation<Parser>(_p) { }

	bool operator()(ParseStream* x, unsigned int start, unsigned int end) const {
		char *name = new char[end-start+1];
		int i = 0;
		while (x->getPosition() < end) {
			name[i] = x->get();
			x->next();
			++i;
		}
		name[i] = 0;
		AutoPointer<NodeTree> nmb(new FunctionCallNode(name, end-start+1));
		this->getParser()->push(nmb);
		return true;
	}
};*/

template<typename Parser>
class FunctionCall : public Operation<Parser> {
public:
	FunctionCall(Parser* _p) : Operation<Parser>(_p) { }

	bool operator()(ParseStream* , unsigned int , unsigned int ) const {
		AutoPointer<NodeTree> a = this->getParser()->top();
		this->getParser()->pop();
		AutoPointer<NodeTree> b = this->getParser()->top();
		this->getParser()->pop();
		this->getParser()->push( AutoPointer<NodeTree>(new ParameterFunctionNode(b, a)) );
		return true;
	}
};

template<typename Parser>
class FunctionVoidCall : public Operation<Parser> {
public:
	FunctionVoidCall(Parser* _p) : Operation<Parser>(_p) { }

	bool operator()(ParseStream* , unsigned int , unsigned int ) const {
		AutoPointer<NodeTree> a = this->getParser()->top();
		this->getParser()->pop();
		this->getParser()->push( AutoPointer<NodeTree>(new ParameterFunctionNode(a, AutoPointer<NodeTree>())) );
		return true;
	}
};

/*template<typename Parser>
class FunctionNameDef : public Operation<Parser> {
public:
	FunctionNameDef(Parser* _p) : Operation<Parser>(_p) { }

	bool operator()(ParseStream* x, unsigned int start, unsigned int end) const {
		char *name = new char[end-start+1];
		int i = 0;
		while (x->getPosition() < end) {
			name[i] = x->get();
			x->next();
			++i;
		}
		name[i] = 0;
		AutoPointer<NodeTree> nmb(new FunctionNameDefinitionNode(name, end-start+1));
		this->getParser()->push(nmb);
		return true;
	}
};*/

template<typename Parser, typename Alloca>
class NameAllocator : public Operation<Parser> {
public:
	NameAllocator(Parser* _p) : Operation<Parser>(_p) { }

	bool operator()(ParseStream* x, unsigned int start, unsigned int end) const {
		char *name = new char[end-start+1];
		int i = 0;
		while (x->getPosition() < end) {
			name[i] = x->get();
			x->next();
			++i;
		}
		name[i] = 0;
		AutoPointer<NodeTree> nmb(new Alloca(name, end-start+1));
		this->getParser()->push(nmb);
		return true;
	}
};

template<typename Parser, typename Node>
class Node1 : public Operation<Parser> {
public:
	Node1(Parser* _p) : Operation<Parser>(_p) { }

	bool operator()(ParseStream* , unsigned int , unsigned int ) const {
		AutoPointer<NodeTree> a = this->getParser()->top();
		this->getParser()->pop();
		this->getParser()->push( AutoPointer<NodeTree>(new Node(a)) );
		return true;
	}
};

template<typename Parser, typename Node>
class Node2 : public Operation<Parser> {
public:
	Node2(Parser* _p) : Operation<Parser>(_p) { }

	bool operator()(ParseStream* , unsigned int , unsigned int ) const {
		AutoPointer<NodeTree> a = this->getParser()->top();
		this->getParser()->pop();
		AutoPointer<NodeTree> b = this->getParser()->top();
		this->getParser()->pop();
		this->getParser()->push( AutoPointer<NodeTree>(new Node(b, a)) );
		return true;
	}
};

template<typename Parser>
class FunctionAllocator : public Operation<Parser> {
public:
	FunctionAllocator(Parser* _p) : Operation<Parser>(_p) { }

	bool operator()(ParseStream* , unsigned int , unsigned int ) const {
		int numInstruction = this->getParser()->getNumberInstruction();
		int numParameter = this->getParser()->getNumberParameter();
		FunctionDefinitionNode* function = new FunctionDefinitionNode();
		while (numInstruction > 0) {//Load the instruction from the stack
			function->addInstruction(this->getParser()->top());
			this->getParser()->pop();
			--numInstruction;
		}
		while (numParameter > 0) {//Load the parameter from the stack
			function->addParameter(this->getParser()->top());//load the type
			this->getParser()->pop();
			function->addParameter(this->getParser()->top());//load the name
			this->getParser()->pop();
			--numParameter;
		}
		function->setName(this->getParser()->top());
		this->getParser()->pop();
		this->getParser()->push( AutoPointer<NodeTree>(function) );
		this->getParser()->setNumberInstruction(0);//restore the parser TODO
		this->getParser()->setNumberParameter(0);//restore the parser
		return true;
	}
};

template<typename Parser>
class IntructionAllocator : public Operation<Parser> {
public:
	IntructionAllocator(Parser* _p) : Operation<Parser>(_p) { }

	bool operator()(ParseStream* , unsigned int , unsigned int ) const {
		this->getParser()->addNumberInstruction();
		return true;
	}
};

template<typename Parser>
class ParameterPatternAllocator : public Operation<Parser> {
public:
	ParameterPatternAllocator(Parser* _p) : Operation<Parser>(_p) { }

	bool operator()(ParseStream* , unsigned int , unsigned int ) const {
		this->getParser()->addNumberParameter();
		return true;
	}
};

template<typename Parser>
class Return : public Operation<Parser> {
public:
	Return(Parser* _p) : Operation<Parser>(_p) { }

	bool operator()(ParseStream* , unsigned int , unsigned int ) const {
		ReturnNode* returnNode = new ReturnNode(this->getParser()->top());
		this->getParser()->pop();
		this->getParser()->push( AutoPointer<NodeTree>(returnNode) );
		this->getParser()->addNumberInstruction();
		return true;
	}
};

template<typename Parser>
class LoadBoolSymbol : public Operation<Parser> {
public:
	LoadBoolSymbol(Parser* _p) : Operation<Parser>(_p) { }

	bool operator()(ParseStream* x, unsigned int start, unsigned int end) const {
		char *name = new char[end-start+1];
		int i = 0;
		while (x->getPosition() < end) {
			name[i] = x->get();
			x->next();
			++i;
		}
		name[i] = 0;
		AutoPointer<NodeTree> nmb(new BoolSymbolNode(name, end-start+1));
		this->getParser()->push(nmb);
		return true;
	}
};

template<typename Parser>
class Boolean : public Operation<Parser> {
public:
	Boolean(Parser* _p) : Operation<Parser>(_p) { }

	bool operator()(ParseStream* , unsigned int , unsigned int ) const {
		AutoPointer<NodeTree> a = this->getParser()->top();
		this->getParser()->pop();
		AutoPointer<NodeTree> b = this->getParser()->top();
		this->getParser()->pop();
		AutoPointer<NodeTree> c = this->getParser()->top();
		this->getParser()->pop();
		this->getParser()->push( AutoPointer<NodeTree>(new BooleanNode(c, a, b)) );
		return true;
	}
};

template<typename Parser>
class InitBlock : public Operation<Parser> {
public:
	InitBlock(Parser* _p) : Operation<Parser>(_p) { }

	bool operator()(ParseStream*, unsigned int , unsigned int) const {
		this->getParser()->pushNumberInstruction(0);
		return true;
	}
};

template<typename Parser>
class IfAllocator : public Operation<Parser> {
public:
	IfAllocator(Parser* _p) : Operation<Parser>(_p) { }

	bool operator()(ParseStream* , unsigned int , unsigned int ) const {
		int numInstruction = this->getParser()->getNumberInstruction();
		IfNode* ifNode = new IfNode();
		while (numInstruction > 0) {//Load the instruction from the stack
			ifNode->addInstruction(this->getParser()->top());
			this->getParser()->pop();
			--numInstruction;
		}
		ifNode->setCondition(this->getParser()->top());//Load the condition
		this->getParser()->pop();
		this->getParser()->push( AutoPointer<NodeTree>(ifNode) );
		this->getParser()->popNumberInstruction();//restore the number instruction of the parser
		this->getParser()->addNumberInstruction();
		return true;
	}
};

template<typename Parser>
class ElseAllocator : public Operation<Parser> {
public:
	ElseAllocator(Parser* _p) : Operation<Parser>(_p) { }

	bool operator()(ParseStream* , unsigned int , unsigned int ) const {
		int numInstruction = this->getParser()->getNumberInstruction();
		IfNode* ifNode = new IfNode();
		while (numInstruction > 0) {//Load the instruction from the stack
			ifNode->addInstruction(this->getParser()->top());
			this->getParser()->pop();
			--numInstruction;
		}
		ifNode->setCondition(this->getParser()->top());//Load the condition
		this->getParser()->pop();
		ElseNode* elseNode = dynamic_cast<ElseNode*>(this->getParser()->top().get());
		if (elseNode) {
			elseNode->addElse( AutoPointer<NodeTree>(ifNode) );
		}
		else {
			elseNode = new ElseNode();
			elseNode->addElse(this->getParser()->top());
			this->getParser()->pop();
			elseNode->addElse( AutoPointer<NodeTree>(ifNode) );
			this->getParser()->push( AutoPointer<NodeTree>(elseNode) );
		}
		this->getParser()->popNumberInstruction();//restore the number instruction of the parser
		//this->getParser()->addNumberInstruction();
		return true;
	}
};

template<typename Parser>
class ElseEndAllocator : public Operation<Parser> {
public:
	ElseEndAllocator(Parser* _p) : Operation<Parser>(_p) { }

	bool operator()(ParseStream* , unsigned int , unsigned int ) const {
		int numInstruction = this->getParser()->getNumberInstruction();
		IfNode* ifNode = new IfNode();
		while (numInstruction > 0) {//Load the instruction from the stack
			ifNode->addInstruction(this->getParser()->top());
			this->getParser()->pop();
			--numInstruction;
		}
		ifNode->setHasCondition(false);
		ElseNode* elseNode = dynamic_cast<ElseNode*>(this->getParser()->top().get());
		if (elseNode) {
			elseNode->setEndElse( AutoPointer<NodeTree>(ifNode) );
		}
		else {
			elseNode = new ElseNode();
			elseNode->addElse(this->getParser()->top());
			this->getParser()->pop();
			elseNode->setEndElse( AutoPointer<NodeTree>(ifNode) );
			this->getParser()->push( AutoPointer<NodeTree>(elseNode) );
		}
		this->getParser()->popNumberInstruction();//restore the number instruction of the parser
		//this->getParser()->addNumberInstruction();
		return true;
	}
};

template<typename Parser>
class WhileAllocator : public Operation<Parser> {
public:
	WhileAllocator(Parser* _p) : Operation<Parser>(_p) { }

	bool operator()(ParseStream* , unsigned int , unsigned int ) const {
		int numInstruction = this->getParser()->getNumberInstruction();
		WhileNode* whileNode = new WhileNode();
		while (numInstruction > 0) {//Load the instruction from the stack
			whileNode->addInstruction(this->getParser()->top());
			this->getParser()->pop();
			--numInstruction;
		}
		whileNode->setCondition(this->getParser()->top());//Load the condition
		this->getParser()->pop();
		this->getParser()->push( AutoPointer<NodeTree>(whileNode) );
		this->getParser()->popNumberInstruction();//restore the number instruction of the parser
		this->getParser()->addNumberInstruction();
		return true;
	}
};

#endif
